#####################################################################
# File:         DataDumpReport.py
# Product:      KnowledgeEngine
#
# Copyright:    Copyright (c) 2002, Faulkner Technologies.
# Author:       Darcy Clark
#
# Description:  This file defines the DataDumpReport class.
#
# See Also:     Component, Model, Section
#####################################################################

#####################################################################
## Knowledge Engine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.KnowledgeEngineCore import *
from Products.KnowledgeEngine.Report import Report, ReportInfo
from Products.KnowledgeEngine.Model.Model import Model
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *

#####################################################################
## Zope Library Imports
from Globals import DTMLFile
from ImageFile import ImageFile

#####################################################################
## Python Library Imports
# (none)

#####################################################################
## DataDumpReportInfo Class Definition
class DataDumpReportInfo(ReportInfo):
    """
        Defines the class info methods, defining information about
        the class without needing an instance of the class
    """
    
    #---------------------------------------------------------------#
    
    def getClassName(self):
        """
            Returns the name of the class for which 
            we are providing information.
        """
        return 'DataDumpReport'

    #---------------------------------------------------------------#

    def getDisplayName(self):
        """
            Return a friendly name for the class instances
            (this is used for displaying in lists etc)
        """
    
        return "Data Dump Report"
        
    #---------------------------------------------------------------#

    def getIdentityType(self):
        """
            Return the identity type.  
        """
        
        return "reportDump"
        
    #---------------------------------------------------------------#
    
    def getClassIcon(self):
        """
            Return the appropriate icon file for the class.
        """
        
        return ImageFile('www/icon.gif', globals())

    #---------------------------------------------------------------#

    def isChildPermitted(self, childClassInfo, childInstance = None):
        """
            Returns if the specified child is permitted as a 
            child of the class' instances.
            
            NOTE: This is from this class' instance perspective.
            
            For component containers, this always overrides what the
            return value from childClassInfo.isPermittedInContainer(...)
        """
        
        #DEFAULT RULE: 360ScoredReports may contain Elements as children
        return childClassInfo.isInstanceOf('Element')
    
    #---------------------------------------------------------------#

    def onConfigureProperties(self):
        """
            Automatically called by the Knowledge Engine once
            the class has been loaded.  Use this method to register 
            class specific properties using the PropertyReflection interface.
            
            If this class is sub-classed, a call must be made to
            the super-class to ensure super-class properties are
            correctly registered
            
            NOTE: This method is called before ClassInfo.onAfterStartup()            
        """

        #initialise the super-class properties for reflection
        ReportInfo.onConfigureProperties(self)

        self.addPropertyDefinition(PropertyDefinition(identity="group", displayName="Select Group", description="Which group of users do you want to dump data for?", propertyType=pt_STRING, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesList=["All","Registered and Locked","Anonymous"], defaultValue="All"))
        self.addPropertyDefinition(PropertyDefinition(identity="scored", displayName="Scored or non-Scored", description="Do you want to dump scored or non-scored (e.g. text) components?", propertyType=pt_STRING, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesList=["All","Scored","Non-Scored"], defaultValue="All"))
        self.addPropertyDefinition(PropertyDefinition(identity="data", displayName="Scores or Answer Content", description="Do you want to display scores or answer content or both?", propertyType=pt_STRING, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesList=["All","Scores","Content"], defaultValue="All"))
        
    #---------------------------------------------------------------#

#####################################################################
## DataDumpReport Class Definition
class DataDumpReport(Report):
    """
        A class to represent a simple report that uses the components
        within the containing Model to build a report
    """

    #---------------------------------------------------------------#

    #ABSTRACT TRANSIENT: a ClassInfo implementation instance to provide info about this class
    _CLASSINFO = DataDumpReportInfo()

    #---------------------------------------------------------------#

    # DTML Methods
    index_html = DTMLFile('dtml/index_html', globals())
    csv_html = DTMLFile('dtml/csv_html', globals())

    #---------------------------------------------------------------#

    def __init__(self, id, identity):
        "Constructor for the DataDumpReport"        

        Report.__init__(self, id, identity)
        
    #---------------------------------------------------------------#

    def getGroup(self):
        "Returns the Group of the model"
        return self.group  

    #---------------------------------------------------------------#
        
    def setGroup(self, group):
        "Sets the Group of the model"
        self.group = group

    #---------------------------------------------------------------#

    def getScored(self):
        "Returns the whether the report lists Scored or Non-Scored Components"
        return self.scored  

    #---------------------------------------------------------------#
        
    def setScored(self, scored):
        "Sets whether the report lists Scored or Non-Scored Components"
        self.scored = scored
        
    #---------------------------------------------------------------#        
        
    def onAfterInstanciation(self):
        """
            Handle Knowledge Engine specific actions after this object 
            has been loaded into memory.  
            
            This is useful for performing backwards compatibility
        """

        #perform BooleanComponent.onAfterInstanciation processing
        Report.onAfterInstanciation(self)
                        
        ###print "DEBUG: CheckBoxComponent.onAfterInstanciation: Completed"

        #add score attribute if it doesn't already exist
        if not hasattr(self, "scored"):
            self.scored = "Scored"

        #add data attribute if it doesn't already exist
        if not hasattr(self, "data"):
            self.data = "All"
            
    #---------------------------------------------------------------#
            
    def getReportType(self):
        """
            Returns the type of report. Options may include
            'single' - a report designed for a single user
            'grouped' - reports designed for grouping assessments
            'dump' - reports designed for data export
            
            by default we return 'single'
        """

        return 'dump'
    
    #---------------------------------------------------------------#

    def getAllAssessments(self):
        """returns list of all assessments
        """

        assessments=[]
        aids=self.getModel().getAssessmentIds()

        for a in aids:
            assessment=self.getModel().getAssessment(a)
            assessments.append(assessment)

        return assessments

    #---------------------------------------------------------------#

    def getAnonAssessments(self):
        """returns list of anonymous assessments
        """

        assessments=[]
        aids=self.getModel().getAssessmentIds()

        for a in aids:
            assessment=self.getModel().getAssessment(a)
            user = assessment.getUser()
            if user == 'unknown':                
                assessments.append(assessment)

        return assessments
        
    #---------------------------------------------------------------#

    def getRegisteredLockedAssessments(self):
        """returns list of registered and locked assessments
        """

        assessments=[]
        aids=self.getModel().getAssessmentIds()

        for a in aids:
            assessment=self.getModel().getAssessment(a)
            user = assessment.getUser()
            if user != 'unknown' and assessment.isLocked():                
                assessments.append(assessment)

        return assessments
        
    #---------------------------------------------------------------#

    def csvDump(self, assessmentlist):
        """            
            Returns a array of data for export.
            Format:
            AID:
            USER:
            STATUS:
            CID,REF,CONTENT,WEIGHTING: DATA
        """

        assessments=assessmentlist

        model=self.getModel()
        modelid=model.getIdentity()
        array=[]
            
        #First Row has Assessment IDs
        aids=[]
        if self.data in ["Scores","All"]:
            aids.extend(['AID:','-','-','-'])
        else:
            aids.extend(['AID:','-','-'])
        for a in assessments:
            if self.data == "All":
                aids.extend([a.getIdentity(),'',''])
            elif self.data == "Content":
                aids.extend([a.getIdentity(),''])
            else:
                aids.append(a.getIdentity())
        array.append(aids)

        #Second Row is Users
        users=[]
        if self.data in ["Scores","All"]:
            users.extend(['USER:','-','-','-'])
        else:
            users.extend(['USER:','-','-'])
        for a in assessments:
            user = a.getUser()
            if user != 'unknown':
                user = user.getUserName()
            if self.data == "All":
                users.extend([user,'',''])
            elif self.data == "Content":
                users.extend([user,''])
            else:
                users.append(user)
                
        array.append(users)

        #Third Row shows status
        status=[]
        if self.data in ["Scores","All"]:
            status.extend(['STATUS:','-','-','-'])
        else:
            status.extend(['STATUS:','-','-'])
        for a in assessments:
            if a.isLocked():
                s = 'locked'
            else:
                s = 'open'
            if self.data == "All":
                status.extend([s,'',''])
            elif self.data == "Content":
                status.extend([s,''])
            else:
                status.append(s)
                
        array.append(status)

        #Fourth Row is padding
        array.append([])
        
        #Fifth Row shows column headings
        headings=[]
        if self.data in ["Scores","All"]:
            headings.extend(['Question Zope ID','Question ID','Question Content','Question Weighting'])
        else:
            headings.extend(['Question Zope ID','Question ID','Question Content'])
        if self.data == "Scores":
            for a in assessments:
                headings.append('Score (Unweighted)')
        elif self.data == "Content":
            for a in assessments:
                headings.extend(['Option Chosen','Report Content'])
        elif self.data == "All":
            for a in assessments:
                headings.extend(['Score (Unweighted)','Option Chosen','Report Content'])
                
        array.append(headings)
       
        #Now itterate through the sections for assessment data
        #Note that we only want scorable components for this data.
        #For ease we will let the section class do all the work
        #That way it will work when we add new scorable components.
        for s in self.getComponentContainers():
            if self.scored == "Scored":
                array.extend(s.csvScoredDump(assessments, self.scored, self.data))
            elif self.scored == "Non-Scored":
                array.extend(s.csvNonScoredDump(assessments, self.scored, self.data))
            elif self.scored == "All":
                array.extend(s.csvAllDump(assessments, self.scored, self.data))
                
        return array
    
    #---------------------------------------------------------------#
    
#####################################################################
## Class Initialisation

# Register Class Information with the Knowledge Engine
registerGenericObjectClass(DataDumpReport)

#####################################################################
